package fr.jade.service.fm.reactor;

import java.util.HashSet;
import java.util.Set;

import org.objectweb.fractal.api.Component;
import org.objectweb.fractal.api.Interface;
import org.objectweb.fractal.api.NoSuchInterfaceException;
import org.objectweb.fractal.api.control.BindingController;
import org.objectweb.fractal.api.control.ContentController;
import org.objectweb.fractal.api.control.SuperController;

import fr.jade.base.JadeBaseComponent;
import fr.jade.util.FractalNavigator;
import fr.jade.util.FractalUtil;

public class BasicAnalyser extends JadeBaseComponent implements Analyser {

  public Set<Component> analyseFailedComponents(Component failedNode_M){
    log("Analyse failed components");
    Set<Component> failedCmps_M = new HashSet<Component>();
    ContentController cc_M = FractalUtil.getContentController(failedNode_M);
    
    for ( Component failedCmp_M : cc_M.getFcSubComponents() ){
      log(FractalNavigator.getName(failedCmp_M));
      failedCmps_M.add(failedCmp_M);
    }
    return failedCmps_M;
  }

  public Set<Component> analyseImpactedComponents(Set<Component> failedComponents_M){
    log("Analyse impacted components");
    Set<Component> impactedCmps_M = new HashSet<Component>();
    for(Component failedCmp_M : failedComponents_M){
      // all childs non failed are impacted
      try {
        ContentController cc_M = FractalUtil.getOptContentController(failedCmp_M);
        for(Component sub_M : cc_M.getFcSubComponents()){
          if(!failedComponents_M.contains(sub_M)){
            log(FractalNavigator.getName(sub_M)+"(child)");
            impactedCmps_M.add(sub_M);
          }else{
            log(FractalNavigator.getName(sub_M)+"(child failed)");
          }
        }
      } catch (NoSuchInterfaceException ignored) {
        log("Failed "+FractalNavigator.getName(failedCmp_M) + " is primitive");
      }
      // all fathers non failed are impacted
      try{
        SuperController sc_M = FractalUtil.getOptSuperController(failedCmp_M);
        for(Component father_M : sc_M.getFcSuperComponents()){
          if(!failedComponents_M.contains(father_M)){
            log(FractalNavigator.getName(father_M)+"(father)");
            impactedCmps_M.add(father_M);
          }else{
            log(FractalNavigator.getName(father_M)+"(father failed)");
          }
        }
      }catch(NoSuchInterfaceException ignored){
        log("Failed "+FractalNavigator.getName(failedCmp_M) + " is a root component");
      }
      // all sibling non failed which have a binding on a failed are impacted
      for(Component cmp : FractalNavigator.getSiblingOrSelf(failedCmp_M)){
        log("analyse "+FractalNavigator.getName(cmp));
        if(!failedComponents_M.contains(cmp)){
          try {
            BindingController bc = FractalUtil.getBindingController(cmp);
            for(Interface i : FractalNavigator.getClientInterfaces(cmp)){
              try {
                log("analyse "+FractalNavigator.getName(cmp)+"."+i.getFcItfName());
                Object o = bc.lookupFc(i.getFcItfName());
                if(o != null){
                  Component server = ((Interface)o).getFcItfOwner();
                  if(failedComponents_M.contains(server)){
                    log(FractalNavigator.getName(cmp)+"(sibling impacted)");
                    impactedCmps_M.add(cmp);
                  }else{
                    log(FractalNavigator.getName(server) + "(sibling failed)");
                  }
                }else{
                  log(FractalNavigator.getName(cmp)+"."+i.getFcItfName()+"(not bound)");
                }
              } catch (NoSuchInterfaceException e) {
                log("WARNING: should not occur - " + FractalNavigator.getName(cmp));
              }
            }
          } catch (NoSuchInterfaceException e1) {
            log(FractalNavigator.getName(cmp)+" has no client interface");
          }
        }
      }
    }
    return impactedCmps_M;
  }

}
